
<!DOCTYPE html>
<html lang="en" class="loading">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>“浅谈Vue2与Vue3响应式的区别” - Bittersweet.的博客</title>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="google" content="notranslate" />
    <meta name="keywords" content="bittersweet,"> 
    <meta name="description" content="我在学校里做的一些项目，以及遇到的问题的解决方法，希望为有需要的人提供帮助,1、Vue2响应式原理：
在此之前我们先简单的了解一下什么是MVVM：
MVVM虽然是4个字母但是其实是由三个部分组成：Model，View和ViewModel。与MVC相比他是视图模型双向绑定，也,"> 
    <meta name="author" content="Bittersweet.(姚亮)"> 
    <link rel="alternative" href="atom.xml" title="Bittersweet.的博客" type="application/atom+xml"> 
    <link rel="icon" href="/Bittersweet/img/favicon.ico"> 
    
    <meta name="twitter:image:src" content="https://bangdream.moe/img/ident.png"/>
    <meta name="twitter:creator" content="@yourtwitteridhere"/>
    <meta name="twitter:card" content="summary_large_image"/>
    <meta name="twitter:title" content="“浅谈Vue2与Vue3响应式的区别” - Bittersweet.的博客"/>
    <meta name="twitter:description" content="我在学校里做的一些项目，以及遇到的问题的解决方法，希望为有需要的人提供帮助,1、Vue2响应式原理：
在此之前我们先简单的了解一下什么是MVVM：
MVVM虽然是4个字母但是其实是由三个部分组成：Model，View和ViewModel。与MVC相比他是视图模型双向绑定，也,"/>
    <meta property="og:image" content="https://bangdream.moe/img/ident.png"/>
    <meta property="og:image:alt" content="我在学校里做的一些项目，以及遇到的问题的解决方法，希望为有需要的人提供帮助,1、Vue2响应式原理：
在此之前我们先简单的了解一下什么是MVVM：
MVVM虽然是4个字母但是其实是由三个部分组成：Model，View和ViewModel。与MVC相比他是视图模型双向绑定，也,"/>
    <meta property="og:image:width" content="1200"/>
    <meta property="og:image:height" content="600"/>
    <meta property="og:site_name" content="Bittersweet.的博客"/>
    <meta property="og:type" content="object"/>
    <meta property="og:title" content="“浅谈Vue2与Vue3响应式的区别” - Bittersweet.的博客"/>
    <meta property="og:description" content="我在学校里做的一些项目，以及遇到的问题的解决方法，希望为有需要的人提供帮助,1、Vue2响应式原理：
在此之前我们先简单的了解一下什么是MVVM：
MVVM虽然是4个字母但是其实是由三个部分组成：Model，View和ViewModel。与MVC相比他是视图模型双向绑定，也,"/>
    
<link rel="stylesheet" href="/Bittersweet/css/diaspora.css">

    <script>window.searchDbPath = "/Bittersweet/search.xml";</script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap" rel="stylesheet">
<meta name="generator" content="Hexo 6.3.0"></head>

<body class="loading">
    <span id="config-title" style="display:none">Bittersweet.的博客</span>
    <div id="loader"></div>
    <div id="single">
    <div id="top" style="display: block;">
    <div class="bar" style="width: 0;"></div>
    <a class="iconfont icon-home image-icon" href="javascript:;" data-url="http://gitee.com/yao-liang-8848"></a>
    <div title="播放/暂停" class="iconfont icon-play"></div>
    <h3 class="subtitle">“浅谈Vue2与Vue3响应式的区别”</h3>
    <div class="social">
        <div>
            <div class="share">
                <a title="获取二维码" class="iconfont icon-scan" href="javascript:;"></a>
            </div>
            <div id="qr"></div>
        </div>
    </div>
    <div class="scrollbar"></div>
</div>

    <div class="section">
        <div class="article">
    <div class='main'>
        <h1 class="title">“浅谈Vue2与Vue3响应式的区别”</h1>
        <div class="stuff">
            <span>三月 10, 2023</span>
            
  <ul class="post-tags-list" itemprop="keywords"><li class="post-tags-list-item"><a class="post-tags-list-link" href="/Bittersweet/tags/MVVM/" rel="tag">MVVM</a></li><li class="post-tags-list-item"><a class="post-tags-list-link" href="/Bittersweet/tags/Vue/" rel="tag">Vue</a></li><li class="post-tags-list-item"><a class="post-tags-list-link" href="/Bittersweet/tags/web%E5%89%8D%E7%AB%AF/" rel="tag">web前端</a></li><li class="post-tags-list-item"><a class="post-tags-list-link" href="/Bittersweet/tags/%E6%95%99%E5%AF%BC%E6%96%87%E7%AB%A0/" rel="tag">教导文章</a></li></ul>


        </div>
        <div class="content markdown">
            <h1 id="1、Vue2响应式原理："><a href="#1、Vue2响应式原理：" class="headerlink" title="1、Vue2响应式原理："></a>1、Vue2响应式原理：</h1><blockquote>
<p><strong>在此之前我们先简单的了解一下什么是MVVM：</strong></p>
<p>MVVM虽然是4个字母但是其实是由三个部分组成：Model，View和ViewModel。与MVC相比他是视图模型双向绑定，也就是多的那个viewModel。</p>
<table>
<thead>
<tr>
<th>M V VM</th>
<th>解释</th>
</tr>
</thead>
<tbody><tr>
<td>Model</td>
<td>代表数据模型（Vue的data），<strong>数据和业务逻辑</strong>都在Model层中定义；</td>
</tr>
<tr>
<td>View</td>
<td>代表UI视图，负责<strong>数据的展示</strong>（Vue的el）；</td>
</tr>
<tr>
<td>ViewModel</td>
<td>是一个对象，负责<strong>监听 Model 中数据的改变</strong>并且<strong>控制View视图的更新</strong>，处理用户交互操作；</td>
</tr>
</tbody></table>
<ul>
<li><p><strong>Model</strong> 和 <strong>View</strong> 并无直接关联，而是通过 <strong>ViewModel</strong> 来进行交互的（即双向数据绑定），</p>
</li>
<li><p><strong>Model</strong> 和 <strong>ViewModel</strong>之间有着<strong>双向数据绑定的联系</strong>。<br> View的变化可以引起Model的变化，Model的变化也可以引起View变化（类似于浅拷贝）。<code>ViewModel</code>是<code>View</code>和<code>Model</code>层的桥梁，数据会绑定到<code>viewModel</code>层并自动将数据渲染到页面中，视图变化的时候会通知<code>viewModel</code>层更新数据。</p>
</li>
</ul>
</blockquote>
<ul>
<li><h2 id="如何实现的？"><a href="#如何实现的？" class="headerlink" title="如何实现的？"></a>如何实现的？</h2><blockquote>
<h5 id="Vue2响应式原理上采用的数据劫持配合发布者-订阅者的模式的方式"><a href="#Vue2响应式原理上采用的数据劫持配合发布者-订阅者的模式的方式" class="headerlink" title="Vue2响应式原理上采用的数据劫持配合发布者-订阅者的模式的方式"></a>Vue2响应式原理上采用的<strong>数据劫持配合发布者-订阅者的模式</strong>的方式</h5><ul>
<li><p>对于对象，使用<strong>Object.defineProperty()<strong>对数据进行读取拦截等操作，也就是常说的</strong>劫持各个属性的getter和setter</strong>，<strong>当数据更新后发布消息给订阅者，触发相应的监听回调后触发视图更新，这里是MVVM的绑定原理</strong></p>
</li>
<li><p>对于数组，是通过重写更新数组的一系列方法（<strong>slice、replace、push、shift、split、filter等等</strong>）来实现拦截，<strong>其实他本质上就是把原来js，es6等对数组这些进行操作的函数进行了一个包裹，当你使用他包裹的函数对数组进行操作后他就能帮你更新视图从而实现响应式的目的</strong></p>
</li>
</ul>
</blockquote>
</li>
<li><h2 id="存在的问题："><a href="#存在的问题：" class="headerlink" title="存在的问题："></a>存在的问题：</h2><ul>
<li><blockquote>
<ul>
<li><h5 id="从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”"><a href="#从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”" class="headerlink" title="从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”"></a>从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”</h5><h5 id="显然，这样子会存在某些问题"><a href="#显然，这样子会存在某些问题" class="headerlink" title="显然，这样子会存在某些问题"></a>显然，这样子会存在某些问题</h5></li>
<li><p><strong>问题1：</strong>例如上面我说的，对于数组，是通过包裹一些函数，那么如果我使用没有被他包裹的函数那么答案很显然，我们的界面是不会更新，不仅如此，如果我们直接对数组的下标进行修改，也不可以</p>
<p>即：</p>
<pre class="line-numbers language-none"><code class="language-none">   let arr&#x3D;[&quot;dad&quot;,&quot;what&quot;,&quot;me&quot;];
   arr&#x3D;arr.filter((str)&#x3D;&gt;&#123;
     return str&#x3D;&#x3D;&#x3D;&#39;dad&#39;
   &#125;)
   console.log(arr);  &#x2F;&#x2F;filter是被vue2包裹的方法，这里过滤掉了what和me，那么界面上呈现的就会更新只剩dad。
而如果通过下标如：
arr[1]&#x3D;&#39;&#39;这样子进行修改，那么界面不会更新<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p><strong>问题2：</strong>如果我们对对象直接进行增删属性的操作，界面不会更新，必须得通过this.$set()来新增，删除用this.$delete</p>
</li>
</ul>
</blockquote>
</li>
</ul>
</li>
</ul>
<h1 id="2、Vue3响应式又是如何做的呢？"><a href="#2、Vue3响应式又是如何做的呢？" class="headerlink" title="2、Vue3响应式又是如何做的呢？"></a>2、Vue3响应式又是如何做的呢？</h1><blockquote>
<p><strong>首先，既然，vue3是对于vue2的更高版本，那么对于vue2存在的问题必然是要解决的，像上述存在的两个问题点，在vue3中都得以解决，这依赖于我们的reactive（）， 把数组对象什么的给塞里面，全都变成了响应式的，并且他还是深层次，非常的好用，非常的神奇，当你对reactive里的对象用console.log去看的时候你会发现，在前面他们有Proxy这个单词</strong></p>
</blockquote>
<ul>
<li><h2 id="没错，主要就是通过proxy（代理）和reflect"><a href="#没错，主要就是通过proxy（代理）和reflect" class="headerlink" title="没错，主要就是通过proxy（代理）和reflect"></a>没错，主要就是通过proxy（代理）和reflect</h2></li>
</ul>
<blockquote>
<ol>
<li>proxy代理是ES6新出的功能，当你对他代理的目标对象进行修改和查探等操作时，他都知道。</li>
</ol>
<p><strong><code>Proxy</code>接受两个参数：</strong></p>
<p><strong>第一个参数是所要代理的目标对象（上例是一个<code>data</code>对象），即如果没有<code>Proxy</code>的介入，操作原来要访问的就是这个<code>data</code>对象。这里的对象是指对象类型(数组也是对象类型)。</strong></p>
<p><strong>第二个参数是一个配置对象<code>handler</code>，对于每一个被代理的操作，需要提供一个对应的处理函数，该函数将拦截对应的操作。比如，上面代码中，配置对象有一个<code>get</code>方法，用来拦截对目标对象属性的访问请求。<code>get</code>方法的两个参数分别是目标对象和所要访问的属性。</strong></p>
<p>2.<code>Reflect</code>也是ES6新增的API。<code>Reflect</code>对象和<code>Proxy</code>对象一样也是用来操作对象的，但是<code>Reflect</code>对象的设计目的有重大的意义。</p>
<ul>
<li><code>Reflect</code>是一个内置的对象，它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象，因此它是不可构造的。<code>Reflect</code>的所有的方法都是静态的就和<code>Math</code>一样，目前它还没有静态属性</li>
</ul>
</blockquote>

            <!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->
            <audio id="audio" loop="1" preload="auto" controls="controls" data-autoplay="false">
                <source type="audio/mpeg" src="">
            </audio>
            
                <ul id="audio-list" style="display:none">
                    
                        
                            <li title="0" data-url="http://link.hhtjim.com/163/425570952.mp3"></li>
                        
                    
                        
                            <li title="1" data-url="http://link.hhtjim.com/163/425570952.mp3"></li>
                        
                    
                </ul>
            
        </div>
        
        
    <div id="gitalk-container" class="comment link"
		data-enable="false"
        data-ae="false"
        data-ci=""
        data-cs=""
        data-r=""
        data-o=""
        data-a=""
        data-d="false"
    >查看评论</div>


    </div>
    
        <div class="side">
            <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1%E3%80%81Vue2%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86%EF%BC%9A"><span class="toc-number">1.</span> <span class="toc-text">1、Vue2响应式原理：</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%9F"><span class="toc-number">1.1.</span> <span class="toc-text">如何实现的？</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#Vue2%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86%E4%B8%8A%E9%87%87%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8A%AB%E6%8C%81%E9%85%8D%E5%90%88%E5%8F%91%E5%B8%83%E8%80%85-%E8%AE%A2%E9%98%85%E8%80%85%E7%9A%84%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%96%B9%E5%BC%8F"><span class="toc-number">1.1.0.0.1.</span> <span class="toc-text">Vue2响应式原理上采用的数据劫持配合发布者-订阅者的模式的方式</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%9A"><span class="toc-number">1.2.</span> <span class="toc-text">存在的问题：</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BB%8E%E4%B8%AD%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BAvue2%E5%AF%B9%E5%93%8D%E5%BA%94%E5%BC%8F%E7%9A%84%E5%A4%84%E7%90%86%E5%A5%BD%E5%83%8F%E6%9C%89%E9%82%A3%E4%B9%88%E4%B8%80%E7%82%B9%E7%9A%84%E2%80%9C%E7%B2%97%E6%9A%B4%E2%80%9D"><span class="toc-number">1.2.0.0.1.</span> <span class="toc-text">从中我们可以看出vue2对响应式的处理好像有那么一点的“粗暴”</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%98%BE%E7%84%B6%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%AD%90%E4%BC%9A%E5%AD%98%E5%9C%A8%E6%9F%90%E4%BA%9B%E9%97%AE%E9%A2%98"><span class="toc-number">1.2.0.0.2.</span> <span class="toc-text">显然，这样子会存在某些问题</span></a></li></ol></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2%E3%80%81Vue3%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8F%88%E6%98%AF%E5%A6%82%E4%BD%95%E5%81%9A%E7%9A%84%E5%91%A2%EF%BC%9F"><span class="toc-number">2.</span> <span class="toc-text">2、Vue3响应式又是如何做的呢？</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B2%A1%E9%94%99%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%B0%B1%E6%98%AF%E9%80%9A%E8%BF%87proxy%EF%BC%88%E4%BB%A3%E7%90%86%EF%BC%89%E5%92%8Creflect"><span class="toc-number">2.1.</span> <span class="toc-text">没错，主要就是通过proxy（代理）和reflect</span></a></li></ol></li></ol>
        </div>
    
</div>


    </div>
</div>
<script src="/Bittersweet/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/Bittersweet/live2dw/assets/assets/koharu.model.json"},"display":{"position":"right","width":200,"height":400},"mobile":{"show":true},"react":{"opacity":0.8},"log":false});</script></body>


<script src="//lib.baomitu.com/jquery/1.8.3/jquery.min.js"></script>
<script src="/Bittersweet/js/plugin.js"></script>
<script src="/Bittersweet/js/typed.js"></script>
<script src="/Bittersweet/js/diaspora.js"></script>


<link rel="stylesheet" href="/Bittersweet/photoswipe/photoswipe.css">
<link rel="stylesheet" href="/Bittersweet/photoswipe/default-skin/default-skin.css">


<script src="/Bittersweet/photoswipe/photoswipe.min.js"></script>
<script src="/Bittersweet/photoswipe/photoswipe-ui-default.min.js"></script>


<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>
    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">
        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>
        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">
            <div class="pswp__top-bar">
                <!--  Controls are self-explanatory. Order can be changed. -->
                <div class="pswp__counter"></div>
                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
                <button class="pswp__button pswp__button--share" title="Share"></button>
                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                      <div class="pswp__preloader__cut">
                        <div class="pswp__preloader__donut"></div>
                      </div>
                    </div>
                </div>
            </div>
            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div> 
            </div>
            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>
            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>
            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>
        </div>
    </div>
</div>



<script type="text/x-mathjax-config">
    MathJax.Hub.Config({"HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"], linebreaks: { automatic:true }, EqnChunk: (MathJax.Hub.Browser.isMobile ? 10 : 50) },
        tex2jax: { inlineMath: [ ["$", "$"], ["\\(","\\)"] ], processEscapes: true, ignoreClass: "tex2jax_ignore|dno",skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']},
        TeX: {  noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } }, Macros: { href: "{}" } },
        messageStyle: "none"
    });
</script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for(i=0; i < all.length; i += 1) {
            all[i].SourceElement().parentNode.className += ' has-jax';
        }
    });
</script>

<script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML">
</script>




</html>
